package com.pjmike.netty.protocol.message.decoder;

import com.pjmike.netty.protocol.message.command.Command;
import com.pjmike.netty.protocol.message.packet.request.AuthRequestPacket;
import com.pjmike.netty.protocol.message.packet.request.VO.CinemaLaneVO;
import com.pjmike.netty.protocol.message.packet.request.VO.CinemaVO;
import com.pjmike.netty.protocol.message.packet.request.VO.LaneVO;
import com.pjmike.netty.utils.Crc32Util;
import com.pjmike.netty.utils.DataTransformUtil;
import com.pjmike.netty.utils.StringUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;

import java.util.zip.CRC32;
import java.util.ArrayList;
import java.util.List;

/**
 * 认证编码器
 *
 * @author lujunjie
 * @create 2021-01-09 09:10
 */
@Slf4j
public class AuthDecoder extends ByteToMessageDecoder {
    //认证报文长度
//    private static int MESSAGE_LENGTH = ;

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        if (!check(in)) {
            log.error("认证检验到非法报文，{}", StringUtil.getByteBufByteHexString(in));
            return;
        }
        in.markReaderIndex();
        //报文头
        short header = in.readByte();
        //协议号
        int protocolNo = in.readUnsignedShort();
        if (protocolNo == Command.AUTH_REQUEST) {
            AuthRequestPacket authRequestPacket = new AuthRequestPacket();
            //1、报文头
            authRequestPacket.setBt(header);
            //2、协议号
            authRequestPacket.setProtocolNo(protocolNo);
            //3、设备编号
            byte[] sbbhbytes = new byte[15];
            in.readBytes(sbbhbytes);
            authRequestPacket.setSbbh(new String(sbbhbytes, 0, 15));

            //4、数据长度
            long sjcd = in.readUnsignedInt();
            authRequestPacket.setSjcd(sjcd);
            //5、ip地址
            byte[] ipdzbytes = new byte[15];
            in.readBytes(ipdzbytes);
            authRequestPacket.setIp(new String(ipdzbytes, 0, 15));
            //6、协议版本
            short bb = in.readUnsignedByte();
            authRequestPacket.setBb(bb);
            //7、设备位置描述
            byte[] sbwzmsbytes = new byte[50];
            in.readBytes(sbwzmsbytes);
            authRequestPacket.setSbwzms(new String(sbwzmsbytes, 0, 50));

            //8、设备位置经度
            byte[] sbwzjdbytes = new byte[30];
            in.readBytes(sbwzjdbytes);
            authRequestPacket.setSbwzjd(new String(sbwzjdbytes, 0, 30));
            //9、设备位置纬度
            byte[] sbwzwdbytes = new byte[30];
            in.readBytes(sbwzwdbytes);
            authRequestPacket.setSbwzwd(new String(sbwzwdbytes, 0, 30));
            //10、车道总数
            short cdzsbytes = in.readUnsignedByte();
            authRequestPacket.setCdzs(cdzsbytes);
            List<LaneVO> laneVOList = new ArrayList<LaneVO>();
            for (int i = 0; i < (int) cdzsbytes; i++) {
                LaneVO laneVO = new LaneVO();
                //11、车道编号
                byte[] cdbhkbytes = new byte[2];
                in.readBytes(cdbhkbytes);
                laneVO.setCdbhk(new String(cdbhkbytes, 0, 2));
                //12、车道类型
                short cdlxk = in.readUnsignedByte();
                laneVO.setCdlxk(cdlxk);
                //13、车道进出口类型
                short cdjcklxk = in.readUnsignedByte();
                laneVO.setCdjcklxk(cdjcklxk);
                //14、车道方向
                short cdfxk = in.readUnsignedByte();
                laneVO.setCdfxk(cdfxk);
                //15、车辆流向
                short cdlxl = in.readUnsignedByte();
                laneVO.setCdlxl(cdlxl);
                laneVOList.add(laneVO);
            }
            authRequestPacket.setLaneVOList(laneVOList);
            //16、摄像机总数
            short sxjzsbytes = in.readUnsignedByte();
            authRequestPacket.setSxjzs(sxjzsbytes);
            List<CinemaVO> sxjzsList = new ArrayList<>();
            for (short i = 0; i < sxjzsbytes; i++) {
                CinemaVO cinemaVO = new CinemaVO();
                //17、摄像机编号
                short sxjbhbytes = in.readUnsignedByte();
                cinemaVO.setSxjbh(sxjbhbytes);
                //18、摄像机类型
                short sxjlxbytes = in.readUnsignedByte();
                cinemaVO.setSxjlx(sxjlxbytes);
                //19、摄像机对应车道数量
                short sxjdycdslbytes = in.readUnsignedByte();
                cinemaVO.setSxjdycdsl(sxjdycdslbytes);
                List<CinemaLaneVO> cinemaLaneVOList = new ArrayList<CinemaLaneVO>();
                for (int j = 0; j < (int) sxjdycdslbytes; j++) {
                    CinemaLaneVO cinemaLaneVO = new CinemaLaneVO();
                    byte[] sxjcdhbytes = new byte[2];
                    in.readBytes(sxjcdhbytes);
                    cinemaLaneVO.setSxjdycdh(new String(sxjcdhbytes, 0, 2));
                    cinemaLaneVOList.add(cinemaLaneVO);
                }
                cinemaVO.setCinemaLaneVO(cinemaLaneVOList);

                //21、摄像机ip地址
                byte[] sxjipbytes = new byte[15];
                in.readBytes(sxjipbytes);
                cinemaVO.setSxjipdz(new String(sxjipbytes, 0, 15));

                //22、摄像机ip流媒体地址
                byte[] sxjiplmtbytes = new byte[128];
                in.readBytes(sxjiplmtbytes);
                cinemaVO.setSxjlmtdz(new String(sxjiplmtbytes, 0, 128));

                sxjzsList.add(cinemaVO);
            }
            authRequestPacket.setCinemaVOList(sxjzsList);

            //23、数据校验
            authRequestPacket.setSjjy(in.readUnsignedInt());
            //24、数据包尾
            authRequestPacket.setBw(in.readUnsignedByte());
            log.info("获取到认证报文，内容：{}", authRequestPacket);
            out.add(authRequestPacket);
        } else {
            in.resetReaderIndex();
            ByteBuf frame = in.retainedDuplicate();
            out.add(frame);
            in.skipBytes(in.readableBytes());
        }
    }

    /**
     * @return boolean
     * @Author bj
     * @Description //校验报文
     * @Date 11:54 2021/1/10
     * @Param [in]
     **/
    private boolean check(ByteBuf in) {
        return Crc32Util.checkMessageFromByteBuf(in);
    }
}
